/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package servlet;

import java.io.IOException;
import java.io.PrintWriter;
import java.lang.Boolean;
import java.util.Calendar;
import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.apache.bcel.generic.CHECKCAST;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/**
 *
 * @author NoiR
 */
public class AjaxActionServlet extends HttpServlet {

    private final String historyfolder = "/xml/history/";
    private final String songxml = "/xml/Songs.xml";

    /**
     * Processes requests for both HTTP <code>GET</code> and <code>POST</code> methods.
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        try {
            String action = request.getParameter("action");
            int id = Integer.parseInt(request.getParameter("id"));
            int sid = Integer.parseInt(request.getParameter("songid"));
            int isType = Integer.parseInt(request.getParameter("type"));

            String realPath = this.getServletContext().getRealPath("/");
            // New Date
            Date date = new Date();
            date.getTime();
            // New calendar and set Today!
            Calendar cal = Calendar.getInstance();
            cal.setTime(date);
            // get year, day, week.
            int year = cal.get(Calendar.YEAR);
            int month = cal.get(Calendar.MONTH);
            int day = cal.get(Calendar.DATE);
            int week = cal.get(Calendar.WEEK_OF_YEAR);
            // get path and checking file exist.
            String fileName = "week" + week + ".xml";
            String path = realPath + historyfolder + year + "/" + fileName;
            String webPath = "web/" + historyfolder + year + "/" + fileName;
            String songxmlpath = realPath + songxml;
            if (!utils.Utils.checkFileExist(path)) {
                xmlutils.XMLUtils.createViewHistoryXML(path, day, month + 1, week);
            }
            if (!utils.Utils.checkFileExist(webPath)) {
                xmlutils.XMLUtils.createViewHistoryXML(webPath, day, month + 1, week);
            }

            // Parse DOM and XPathFactory
            Document doc = xmlutils.XMLUtils.parseDOM(path);
            Document sdoc = xmlutils.XMLUtils.parseDOM(songxmlpath);
            XPathFactory xpf = XPathFactory.newInstance();
            XPath xp = xpf.newXPath();

            if ("view".equals(action)) {
                // process for Song or Album
                if (isType == 1) {
                    String exp = "//*[local-name()='SongID' and normalize-space(text())='" + id + "']/parent::*/*[local-name()='Views']";

                    if ((Boolean) xp.evaluate(exp, doc, XPathConstants.BOOLEAN)) {
                        // found then edit
                        Node found = (Node) xp.evaluate(exp, doc, XPathConstants.NODE);
                        int tmp = Integer.parseInt(found.getTextContent().trim());
                        found.setTextContent("" + (++tmp) + "");
                    } else {
                        // not found then add
                        if (prepareNewElement("song", doc, id)) {
                        } else {
                            System.out.println("Prepare element error.");
                        }
                    }
                } else if (isType == 2) {
                    String albumExp = "//*[local-name()='AlbumID' and normalize-space(text())='" + id + "']/parent::*/*[local-name()='Views']";
                    String songExp = "//*[local-name()='SongID' and normalize-space(text())='" + sid + "']/parent::*/*[local-name()='Views']";

                    // process for album
                    if ((Boolean) xp.evaluate(albumExp, doc, XPathConstants.BOOLEAN)) {
                        // found then edit
                        Node found = (Node) xp.evaluate(albumExp, doc, XPathConstants.NODE);
                        int tmp = Integer.parseInt(found.getTextContent().trim());
                        found.setTextContent("" + (++tmp));
                    } else {
                        // not found then add
                        if (prepareNewElement("album", doc, id)) {
                        } else {
                            System.out.println("Prepare element error.");
                        }
                    }
                    // process for song
                    if ((Boolean) xp.evaluate(songExp, doc, XPathConstants.BOOLEAN)) {
                        // found then edit
                        Node found = (Node) xp.evaluate(songExp, doc, XPathConstants.NODE);
                        int tmp = Integer.parseInt(found.getTextContent().trim());
                        found.setTextContent("" + (++tmp));
                    } else {
                        // not found then add
                        if (prepareNewElement("song", doc, sid)) {
                        } else {
                            System.out.println("Prepare element error.");
                        }
                    }
                }
                // after processed song, album then artist.
                String artistExp = "//*[local-name()='SongID' and normalize-space(text())='" + sid + "']/parent::*//*[local-name()='ArtistID']";
                if ((Boolean) xp.evaluate(artistExp, sdoc, XPathConstants.BOOLEAN)) {
                    // found then edit
                    NodeList artists = (NodeList) xp.evaluate(artistExp, sdoc, XPathConstants.NODESET);
                    for (int i = 0; i < artists.getLength(); i++) {
                        String artistExp2 = "//*[local-name()='ArtistID' and normalize-space(text())='" + artists.item(i).getTextContent() + "']/parent::*/*[local-name()='Views']";
                        if ((Boolean) xp.evaluate(artistExp2, doc, XPathConstants.BOOLEAN)) {
                            // found then edit
                            Node found = (Node) xp.evaluate(artistExp2, doc, XPathConstants.NODE);
                            int tmp = Integer.parseInt(found.getTextContent().trim());
                            found.setTextContent("" + (++tmp));
                        } else {
                            // not found then add
                            if (prepareNewElement("artist", doc, Integer.parseInt(artists.item(i).getTextContent()))) {
                            } else {
                                System.out.println("Prepare element error.");
                            }
                        }
                    } // end for
                } // end check artist exist
                xmlutils.XMLUtils.writeXML(doc, path);
                xmlutils.XMLUtils.writeXML(doc, webPath);
            } // end check action
        } catch (XPathExpressionException ex) {
            Logger.getLogger(AjaxActionServlet.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            out.close();
        }
    }

    public boolean prepareNewElement(String type, Document doc, int id) {
        // if 1 is song, 2 is album
        NodeList list = null;
        try {
            if ("song".equals(type)) {
                Element e = doc.createElement("Song");

                Element eid = doc.createElement("SongID");
                eid.setTextContent("" + id);
                e.appendChild(eid);

                Element ev = doc.createElement("Views");
                ev.setTextContent("1");
                e.appendChild(ev);

                list = doc.getElementsByTagName("Songs");
                list.item(0).appendChild(e);
            } else if ("album".equals(type)) {
                Element e = doc.createElement("Album");

                Element eid = doc.createElement("AlbumID");
                eid.setTextContent("" + id);
                e.appendChild(eid);

                Element ev = doc.createElement("Views");
                ev.setTextContent("1");
                e.appendChild(ev);

                list = doc.getElementsByTagName("Albums");
                list.item(0).appendChild(e);
            } else if ("artist".equals(type)) {
                Element e = doc.createElement("Artist");

                Element eid = doc.createElement("ArtistID");
                eid.setTextContent("" + id);
                e.appendChild(eid);

                Element ev = doc.createElement("Views");
                ev.setTextContent("1");
                e.appendChild(ev);

                list = doc.getElementsByTagName("Artists");
                list.item(0).appendChild(e);
            }

            return true;
        } catch (Exception e) {
            return false;
        }
    }

    // <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code.">
    /** 
     * Handles the HTTP <code>GET</code> method.
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    /** 
     * Handles the HTTP <code>POST</code> method.
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    /** 
     * Returns a short description of the servlet.
     * @return a String containing servlet description
     */
    @Override
    public String getServletInfo() {
        return "Short description";
    }// </editor-fold>
}
